home *** CD-ROM | disk | FTP | other *** search
/ Tech Win 1999 February / TECH Win 02-1999 Disc A.iso / ols / lzh / tcl211.lzh / DLLSRC.lzh / startbtn.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-10-27  |  10.7 KB  |  414 lines

  1. /*-------------------------------------------
  2.  STARTBTN.C
  3.   スタートボタンの改造
  4.   KAZUBON 1997
  5. ---------------------------------------------*/
  6.  
  7. #include "tcdll.h"
  8.  
  9. extern HANDLE hmod;
  10.  
  11. /*------------------------------------------------
  12.  Globals
  13. --------------------------------------------------*/
  14. WNDPROC oldWndProcStart = NULL, oldWndProcTask = NULL;
  15. HWND hwndStart = NULL, hwndTask = NULL, hwndTray = NULL;
  16. HBITMAP hbmpstart = NULL, hbmpstartold = NULL;
  17. int wStart = -1, hStart = -1;
  18.  
  19. static void SetStartButtonBmp(void);
  20. static void SetTaskWinPos(void);
  21.  
  22. /*------------------------------------------------
  23.  スタートボタンのサブクラスプロシージャ
  24. --------------------------------------------------*/
  25. LRESULT CALLBACK WndProcStart(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  26. {
  27.     switch(message)
  28.     {
  29.         case WM_SYSCOLORCHANGE:  // システムの設定変更
  30.         case WM_WININICHANGE:
  31.             if(IsWindowVisible(hwnd))
  32.                 PostMessage(hwnd, WM_USER+10, 0, 0L);
  33.             return 0;
  34.         case (WM_USER + 10):     // 再初期化
  35.             SetStartButtonBmp();
  36.             return 0;
  37.         case WM_WINDOWPOSCHANGING:  // サイズを変更させない
  38.         {
  39.             LPWINDOWPOS pwp;
  40.             pwp = (LPWINDOWPOS)lParam;
  41.             if(!(pwp->flags & SWP_NOSIZE))
  42.             {
  43.                 if(wStart > 0) pwp->cx = wStart;
  44.                 if(hStart > 0) pwp->cy = hStart;
  45.             }
  46.             if(!IsWindowVisible(hwnd))
  47.             {
  48.                 RECT rc; POINT pt;
  49.                 GetWindowRect(hwndTray, &rc);
  50.                 pt.x = rc.left; pt.y = rc.top;
  51.                 ScreenToClient(GetParent(hwndTray), &pt);
  52.                 pwp->x = pt.x; pwp->y = pt.y;
  53.                 pwp->cx = rc.right - rc.left;
  54.                 pwp->cy = rc.bottom - rc.top;
  55.             }
  56.             break;
  57.         }
  58.         case WM_DESTROY:
  59.             SendMessage(hwndStart, BM_SETIMAGE,
  60.                 0, (LPARAM)hbmpstartold);
  61.             hbmpstartold = NULL;
  62.             if(hbmpstart) DeleteObject(hbmpstart); hbmpstart = NULL;
  63.             break;
  64.     }
  65.     return CallWindowProc(oldWndProcStart, hwnd, message, wParam, lParam);
  66. }
  67.  
  68. /*--------------------------------------------------
  69.  MSTaskSwWClassのサブクラスプロシージャ
  70. ----------------------------------------------------*/
  71. LRESULT CALLBACK WndProcTask(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  72. {
  73.     switch(message)
  74.     {
  75.         case WM_WINDOWPOSCHANGING: // 位置・サイズの制限
  76.         {
  77.             LPWINDOWPOS pwp;
  78.             RECT rcBar, rcTray;
  79.     
  80.             pwp = (LPWINDOWPOS)lParam;
  81.             if((pwp->flags & SWP_NOMOVE) ||
  82.                 wStart < 0 || hStart < 0) break;
  83.             
  84.             GetClientRect(GetParent(hwndStart), &rcBar); // タスクバー
  85.             GetWindowRect(hwndTray, &rcTray); // TrayNotifyWnd
  86.             
  87.             // タスクバーが横置きのとき
  88.             if(rcBar.right > rcBar.bottom)
  89.             {
  90.                 pwp->x = 2 + wStart; // 右位置
  91.                 pwp->cx = rcTray.left - 2 - wStart - 2; // 横幅
  92.                 if(wStart > 0)
  93.                 {
  94.                     pwp->x += 2; pwp->cx -= 2;
  95.                 }
  96.             }
  97.             else // 縦置きのとき
  98.             {
  99.                 if(rcTray.top < pwp->y)
  100.                 {
  101.                     pwp->cy = rcBar.bottom - 2 - hStart - 2; // 高さ
  102.                 }
  103.                 else
  104.                 {
  105.                     pwp->cy = rcTray.top - 2 - hStart - 2; // 高さ
  106.                 }
  107.                 pwp->y = 2 + hStart; // 上位置
  108.                 if(hStart > 0)
  109.                 {
  110.                     pwp->y += 1; pwp->cy -= 2;
  111.                 }
  112.             }
  113.             break;
  114.         }
  115.     }
  116.     return CallWindowProc(oldWndProcTask, hwnd, message, wParam, lParam);
  117. }
  118.  
  119. /*--------------------------------------------------
  120.  スタートボタンの初期化
  121. ----------------------------------------------------*/
  122. void SetStartButton(HWND hwndClock)
  123. {
  124.     BOOL b, bHide;
  125.     HANDLE hwnd;
  126.     char classname[80];
  127.     
  128.     EndStartButton();
  129.     
  130.     // "button"と"MSTaskSwWClass"のウィンドウハンドルを得る
  131.     hwndStart = hwndTask = NULL;
  132.     hwndTray = GetParent(hwndClock); // TrayNotifyWnd
  133.     hwnd = GetParent(hwndTray);      // Shell_TrayWnd
  134.     if(hwnd == NULL) return;
  135.     hwnd = GetWindow(hwnd, GW_CHILD);
  136.     while(hwnd)
  137.     {
  138.         GetClassName(hwnd, classname, 80);
  139.         if(lstrcmpi(classname, "Button") == 0)
  140.             hwndStart = hwnd;
  141.         else if(lstrcmpi(classname, "MSTaskSwWClass") == 0)
  142.             hwndTask = hwnd;
  143.         else if(lstrcmpi(classname, "ReBarWindow32") == 0)
  144.             hwndTask = hwnd;
  145.         hwnd = GetWindow(hwnd, GW_HWNDNEXT);
  146.     }
  147.     if(hwndStart == NULL || hwndTask == NULL)
  148.     {
  149.         hwndStart = hwndTask = NULL; return;
  150.     }
  151.     
  152.     b = GetMyRegLong(NULL, "StartButton", FALSE);
  153.     bHide = GetMyRegLong(NULL, "StartButtonHide", FALSE);
  154.     if(!b && !bHide) return;
  155.     
  156.     // サブクラス化
  157.     oldWndProcStart = (WNDPROC)GetWindowLong(hwndStart, GWL_WNDPROC);
  158.     SetWindowLong(hwndStart, GWL_WNDPROC, (LONG)WndProcStart);
  159.     oldWndProcTask = (WNDPROC)GetWindowLong(hwndTask, GWL_WNDPROC);
  160.     SetWindowLong(hwndTask, GWL_WNDPROC, (LONG)WndProcTask);
  161.     
  162.     if(bHide) // ボタンを隠す
  163.     {
  164.         RECT rc; POINT pt;
  165.         ShowWindow(hwndStart, SW_HIDE);
  166.         wStart = 0; hStart = 0;
  167.         GetWindowRect(hwndTray, &rc);
  168.         pt.x = rc.left; pt.y = rc.top;
  169.         ScreenToClient(GetParent(hwndTray), &pt);
  170.         SetWindowPos(hwndStart, NULL, pt.x, pt.y,
  171.             rc.right - rc.left, rc.bottom - rc.top,
  172.             SWP_NOZORDER|SWP_NOACTIVATE);
  173.     }
  174.     else
  175.     {
  176.         // ボタン用ビットマップの設定
  177.         SetStartButtonBmp();
  178.     }
  179.     // MSTaskSwWClassの位置・サイズの設定
  180.     SetTaskWinPos();
  181. }
  182.  
  183. /*--------------------------------------------------
  184.  スタートボタンを元に戻す
  185. ----------------------------------------------------*/
  186. void EndStartButton(void)
  187. {
  188.     if(hwndStart && IsWindow(hwndStart))
  189.     {
  190.         if(hbmpstartold != NULL)
  191.         {
  192.             SendMessage(hwndStart, BM_SETIMAGE,
  193.                 0, (LPARAM)hbmpstartold);
  194.             hbmpstartold = NULL;
  195.         }
  196.         if(oldWndProcStart)
  197.             SetWindowLong(hwndStart, GWL_WNDPROC, (LONG)oldWndProcStart);
  198.         oldWndProcStart = NULL;
  199.         SetWindowPos(hwndStart, NULL, 0, 0, 0, 0,
  200.             SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
  201.         ShowWindow(hwndStart, SW_SHOW);
  202.     }
  203.     hwndStart = NULL;
  204.     
  205.     if(hbmpstart) DeleteObject(hbmpstart); hbmpstart = NULL;
  206.     
  207.     if(hwndTask && IsWindow(hwndTask) && oldWndProcTask)
  208.         SetWindowLong(hwndTask, GWL_WNDPROC, (LONG)oldWndProcTask);
  209.     oldWndProcTask = NULL; hwndStart = NULL;
  210. }
  211.  
  212. /*--------------------------------------------------
  213.  スタートボタンのビットマップとサイズの設定
  214. ----------------------------------------------------*/
  215. void SetStartButtonBmp(void)
  216. {
  217.     char s[1024], caption[1024];
  218.     HBITMAP hbmpicon, hbmpold;
  219.     HICON hicon;
  220.     HDC hdc, hdcMem;
  221.     HFONT hfont;
  222.     BITMAP bmp;
  223.     int whbmp, hhbmp, cxicon, cyicon;
  224.     BOOL b;
  225.  
  226.     if(hwndStart == NULL) return;
  227.     
  228.     hbmpicon = NULL; hicon = NULL;
  229.     cxicon = GetSystemMetrics(SM_CXSMICON);
  230.     cyicon = GetSystemMetrics(SM_CYSMICON);
  231.     
  232.     // ファイルからアイコン用ビットマップの読み込み
  233.     if(GetMyRegStr(NULL, "StartButtonIcon", s, "") > 0)
  234.     {
  235.         char fname[MAX_PATH], head[2];
  236.         HFILE hf;
  237.         
  238.         parse(fname, s, 0);
  239.         hf = _lopen(fname, OF_READ);
  240.         if(hf != HFILE_ERROR)
  241.         {
  242.             _lread(hf, head, 2);
  243.             _lclose(hf);
  244.             if(head[0] == 'B' && head[1] == 'M') //ビットマップの場合
  245.                 hbmpicon = ReadBitmap(hwndStart, fname, TRUE);
  246.             else if(head[0] == 'M' && head[1] == 'Z') //実行ファイルの場合
  247.             {
  248.                 char numstr[10], *p; int n;
  249.                 HICON hiconl;
  250.                 parse(numstr, s, 1);
  251.                 n = 0; p = numstr;
  252.                 while(*p)
  253.                 {
  254.                     if(*p < '0' || '9' < *p) break;
  255.                     n = n * 10 + *p++ - '0';
  256.                 }
  257.                 if(ExtractIconEx(fname, n, &hiconl, &hicon, 1) < 2)
  258.                     hicon = NULL;
  259.                 else DestroyIcon(hiconl);
  260.             }
  261.             else // アイコンの場合
  262.             {
  263.                 hicon = (HICON)LoadImage(hmod, fname,
  264.                     IMAGE_ICON, cxicon, cyicon,
  265.                     LR_DEFAULTCOLOR|LR_LOADFROMFILE);
  266.             }
  267.         }
  268.     }
  269.     
  270.     if(hbmpicon)
  271.     {
  272.         GetObject(hbmpicon, sizeof(BITMAP), (LPVOID)&bmp);
  273.         cxicon = bmp.bmWidth; cyicon = bmp.bmHeight;
  274.     }
  275.  
  276.     // キャプションの取得
  277.     GetMyRegStr(NULL, "StartButtonCaption", caption, "");
  278.     
  279.     hdc = GetDC(hwndStart);
  280.     
  281.     // ボタン用のフォント = タイトルバーのフォント + BOLD
  282.     hfont = NULL;
  283.     whbmp = cxicon; hhbmp = cyicon;
  284.     if(caption[0])
  285.     {
  286.         NONCLIENTMETRICS ncm;
  287.         SIZE sz;
  288.         ncm.cbSize = sizeof(ncm);
  289.         SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
  290.         ncm.lfCaptionFont.lfWeight = FW_BOLD;
  291.         hfont =  CreateFontIndirect(&(ncm.lfCaptionFont));
  292.         SelectObject(hdc, hfont);
  293.         
  294.         //キャプションの幅を得る
  295.         GetTextExtentPoint32(hdc, caption, strlen(caption), &sz);
  296.         whbmp = sz.cx;
  297.         if(hbmpicon || hicon) whbmp += cxicon + 2;
  298.         hhbmp = sz.cy;
  299.         if((hbmpicon || hicon) && cyicon > sz.cy)
  300.             hhbmp = cyicon;
  301.         //if(hhbmp < 16) hhbmp = 16;
  302.     }
  303.     
  304.     // ビットマップの作成
  305.     hdcMem = CreateCompatibleDC(hdc);
  306.     hbmpstart = CreateCompatibleBitmap(hdc, whbmp, hhbmp);
  307.     SelectObject(hdcMem, hbmpstart);
  308.     
  309.     { // 背景色で塗りつぶし
  310.         RECT rc; HBRUSH hbr;
  311.         SetRect(&rc, 0, 0, whbmp, hhbmp);
  312.         hbr = CreateSolidBrush(GetSysColor(COLOR_3DFACE));
  313.         FillRect(hdcMem, &rc, hbr);
  314.         DeleteObject(hbr);
  315.     }
  316.     
  317.     // ビットマップにアイコンの絵を描画
  318.     if(hbmpicon)
  319.     {
  320.         HDC hdcicon;
  321.         hdcicon = CreateCompatibleDC(hdc);
  322.         SelectObject(hdcicon, hbmpicon);
  323.         BitBlt(hdcMem, 0, (hhbmp - cyicon)/2,
  324.             cxicon, cyicon, hdcicon, 0, 0, SRCCOPY);
  325.         DeleteDC(hdcicon);
  326.         DeleteObject(hbmpicon);
  327.     }
  328.     if(hicon)
  329.     {
  330.         DrawIconEx(hdcMem, 0, (hhbmp - cyicon)/2,
  331.             hicon, cxicon, cyicon, 0, NULL, DI_NORMAL);
  332.         DestroyIcon(hicon);
  333.     }
  334.     
  335.     // ビットマップにキャプションを書く
  336.     if(caption[0])
  337.     {
  338.         TEXTMETRIC tm;
  339.         int x, y;
  340.  
  341.         GetTextMetrics(hdc, &tm);
  342.         SelectObject(hdcMem, hfont);
  343.         x = 0; if(hbmpicon || hicon) x = cxicon + 2;
  344.         y = (hhbmp - tm.tmHeight) / 2;
  345.         SetBkMode(hdcMem, TRANSPARENT);
  346.         SetTextColor(hdcMem, GetSysColor(COLOR_BTNTEXT));
  347.         TextOut(hdcMem, x, y, caption, strlen(caption));
  348.     }
  349.     
  350.     DeleteDC(hdcMem);
  351.     ReleaseDC(hwndStart, hdc);
  352.     if(hfont) DeleteObject(hfont);
  353.  
  354.     // ボタンにビットマップを設定
  355.     hbmpold = (HICON)SendMessage(hwndStart, BM_SETIMAGE, 0, (LPARAM)hbmpstart);
  356.     // 以前のビットマップを保存 / 破棄
  357.     if(hbmpstartold == NULL) hbmpstartold = hbmpold;
  358.     else DeleteObject(hbmpold);
  359.     
  360.     // ボタンのサイズの設定  上限:160x80
  361.     wStart = whbmp + 8;
  362.     if(wStart > 160) wStart = 160;
  363.     hStart = GetSystemMetrics(SM_CYCAPTION) + 3;
  364.     if(hhbmp + 6 > hStart) hStart = hhbmp + 6;
  365.     if(hStart > 80) hStart = 80;
  366.     SetWindowPos(hwndStart, NULL, 0, 0,
  367.         wStart, hStart,
  368.         SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
  369. }
  370.  
  371. /*--------------------------------------------------
  372.  MSTaskSwWClassの位置・サイズの設定
  373. ----------------------------------------------------*/
  374. void SetTaskWinPos(void)
  375. {
  376.     RECT rcBar, rcTask, rcTray;
  377.     POINT pt;
  378.     int x, y, w, h;
  379.  
  380.     GetClientRect(GetParent(hwndStart), &rcBar);  // Shell_TrayWnd
  381.     GetWindowRect(hwndTray, &rcTray); // TrayNotifyWnd
  382.     GetWindowRect(hwndTask, &rcTask);             // MSTaskSwWClass
  383.     
  384.     // MSTaskSwWClassの右上位置
  385.     pt.x = rcTask.left; pt.y = rcTask.top;
  386.     ScreenToClient(GetParent(hwndStart), &pt);
  387.     
  388.     x = pt.x; y = pt.y;
  389.     w = rcTask.right - rcTask.left;
  390.     h = rcTask.bottom - rcTask.top;
  391.     
  392.     // タスクバーが横置きのとき
  393.     if(rcBar.right > rcBar.bottom)
  394.     {
  395.         x = 2 + wStart;
  396.         w = rcTray.left - 2 - wStart - 2;
  397.         if(wStart > 0)
  398.         {
  399.             x += 2; w -= 2;
  400.         }
  401.     }
  402.     else // 縦置きのとき
  403.     {
  404.         y = 2 + hStart;
  405.         h = rcTray.top - 2 - hStart - 2;
  406.         if(hStart > 0)
  407.         {
  408.             y += 1; h -= 2;
  409.         }
  410.     }
  411.     SetWindowPos(hwndTask, NULL, x, y, w, h,
  412.         SWP_NOZORDER|SWP_NOACTIVATE);
  413. }
  414.